// ===----------------------------------------------------------------------===
//
//  Copyright (C) 2022 Sophgo Technologies Inc.  All rights reserved.
//
//  SOPHON-DEMO is licensed under the 2-Clause BSD License except for the
//  third-party components.
//
// ===----------------------------------------------------------------------===

#include "DecoderConsole.h"
#include "EncoderConsole.h"
#include "opencv2/opencv.hpp"
#include <string>
#include <fstream>
#include "common.h"
#include "json.h"
#include "profiler.h"
#include "yolov8.h"
#include "httplib.h"
#include "http_lib_push.h"
#include "http_lib_srv.h"
#include "mqtt_push_console.h"
#include "http_lib_push_console.h"

int main(int argc, char *argv[])
{

    // 解析程序输入的参数，将参数信息放入parser中
    std::string keys = "{config | ./config/yolov8s-seg-drillpipe-count.json | path to config.json}";
    cv::CommandLineParser parser(argc, argv, keys);
    std::string config_file = parser.get<std::string>("config");

    std::ifstream file(config_file.c_str());
    if (!file.is_open())
    {
        std::cerr << "Failed to open json file." << std::endl;
        return 1;
    }
    nlohmann::json config;
    file >> config;

    // 从json文件中读取解码器参数
    std::vector<std::string> decode_url_vec = config["decoder"]["urls"];
    int decode_channel_num = decode_url_vec.size();

    // 从json文件中读取编码器参数
    std::vector<std::string> encode_url_vec = config["encoder"]["urls"];
    int encode_channel_num = encode_url_vec.size();

    // 从json文件中读取http_push的参数
    std::string http_push_ip_port = config["http_push"]["ip_port"];
    std::string http_push_path = config["http_push"]["path"];

    // 从json文件中读取http_srv的参数
    std::string http_srv_ip = config["http_srv"]["ip"];
    int http_srv_port = config["http_srv"]["port"];

    // 从json文件中读取mqtt_push的参数
    std::string mqtt_push_address = config["mqtt_push"]["address"];
    std::string mqtt_push_topic = config["mqtt_push"]["topic"];

    // 从json文件中读取yolov8的参数
    int dev_id = config["yolov8"]["dev_id"];
    std::string bmodel_path = config["yolov8"]["bmodel_path"];
    std::string tpu_kernel_module_path = config["yolov8"]["tpu_kernel_module_path"];
    std::string mask_bmodel_path = config["yolov8"]["mask_bmodel"];
    int que_size = config["yolov8"]["que_size"];
    int skip_num = config["yolov8"]["skip_num"];
    float nmsThreshold = config["yolov8"]["nmsThreshold"];
    float confThreshold = config["yolov8"]["confThreshold"];
    std::vector<std::string> class_name_vec = config["yolov8"]["class_names"];
    int class_name_num = class_name_vec.size();

    // 从json文件中读取drill_pipe_judge的参数
    int drill_pipe_angle_change_threshold_by_degree = config["drill_pipe_judge"]["angle_change_threshold_by_degree"];
    int drill_pipe_angle_judge_continuous_time_by_second = config["drill_pipe_judge"]["angle_judge_continuous_time_by_second"];
    int drill_pipe_angle_continuous_stable_judge_time_by_second = config["drill_pipe_judge"]["angle_continuous_stable_judge_time_by_second"];

    // 开启视频编码器  目前这个编码器还有问题，推送有问题，暂时注释掉
    // EncoderConsole multi_enc;
    // for (int i = 0; i < encode_url_vec.size(); i++)
    // {
    //     multi_enc.addChannel(encode_url_vec[i]);
    // }

    // 开启视频解码器
    DecoderConsole multi_dec;
    for (int i = 0; i < decode_url_vec.size(); i++)
    {
        multi_dec.addChannel(decode_url_vec[i]);
    }
    std::this_thread::sleep_for(std::chrono::seconds(3));

    // 初始化yolov8模型
    YoloV8 yolov8(dev_id, bmodel_path, tpu_kernel_module_path, mask_bmodel_path, que_size, skip_num, nmsThreshold, confThreshold, class_name_num);
    yolov8.setClassNames(class_name_vec);

    // 开启http lib push推流
    HttpLibPush httpLibPush(http_push_ip_port,
                            http_push_path,
                            drill_pipe_angle_change_threshold_by_degree,
                            drill_pipe_angle_judge_continuous_time_by_second,
                            drill_pipe_angle_continuous_stable_judge_time_by_second);
    for (int i = 0; i < decode_url_vec.size(); i++)
    {
        httpLibPush.add_channel(i, decode_url_vec[i]);
    }

    // 推送线程，将结果推送给前端
    std::thread http_push_thread([&]()
                                 {
        FpsProfiler fpsApp("http_push",100);
        while(true){
                auto ptr = yolov8.get_img();
                // if( ptr-> is_mask)
                {
                    httpLibPush.push_img(ptr->channel_id,ptr);
                }
                fpsApp.add(1);
        } });
    http_push_thread.detach();
#if 0
    下面是多线程推流,mqtt和http_lib_push推流,暂时注释掉

    // 开启mqtt推流
    MqttPush mqtt_push(mqtt_push_address, mqtt_push_topic);
    Mqtt_push_console mqtt_push_console;
    for (int i = 0; i < decode_url_vec.size(); i++)
    {
        mqtt_push_console.add_channel(mqtt_push_address, mqtt_push_topic);
    }

    Http_lib_push_console http_lib_push_console;
    for (int i = 0; i < decode_url_vec.size(); i++)
    {
        http_lib_push_console.add_channel(http_push_ip_port, http_push_path);
    }


    // 推送线程，将结果推送给mqtt broker
    std::thread push_thread([&]()
                                 {
        FpsProfiler fpsApp("push_thread",100);
        while(true){
                auto ptr = yolov8.get_img();
                if( ptr-> is_mask)
                {
                    // mqtt_push_console.push_img(ptr->channel_id,ptr);
                    http_lib_push_console.push_img(ptr->channel_id,ptr);
                }
                fpsApp.add(1);
        } });
    push_thread.detach();
#endif
    // 解码线程 ，开启AI处理
    std::thread decode_thread([&]()
                              {
        FpsProfiler fpsApp("yolov8-seg detect",100);
        //启动编码器
        while(true){
            for(int channel_id=0; channel_id < decode_channel_num ;channel_id++){
                std::shared_ptr<bm_image> image;
                if(multi_dec.read(channel_id, image)==0){
                    
                    yolov8.push_img(channel_id, image);
                    fpsApp.add(1);
                }
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(5));
        } });

    decode_thread.detach();

    // 开启http服务端
    HttpLibSrv http_srv(http_srv_ip, http_srv_port);

    return 0;
}